; haribote-os boot asm
; TAB=4

BOTPAK	EQU		0x00280000		; bootpack‚Ìƒ[ƒhæ
DSKCAC	EQU		0x00100000		; ƒfƒBƒXƒNƒLƒƒƒbƒVƒ…‚ÌêŠ
DSKCAC0	EQU		0x00008000		; ƒfƒBƒXƒNƒLƒƒƒbƒVƒ…‚ÌêŠiƒŠƒAƒ‹ƒ‚[ƒhj

; BOOT_INFOŠÖŒW
CYLS	EQU		0x0ff0			; ƒu[ƒgƒZƒNƒ^‚ªÝ’è‚·‚é
LEDS	EQU		0x0ff1
VMODE	EQU		0x0ff2			; F”‚ÉŠÖ‚·‚éî•ñB‰½ƒrƒbƒgƒJƒ‰[‚©H
SCRNX	EQU		0x0ff4			; ‰ð‘œ“x‚ÌX
SCRNY	EQU		0x0ff6			; ‰ð‘œ“x‚ÌY
VRAM	EQU		0x0ff8			; ƒOƒ‰ƒtƒBƒbƒNƒoƒbƒtƒ@‚ÌŠJŽn”Ô’n

		ORG		0xc200			; ‚±‚ÌƒvƒƒOƒ‰ƒ€‚ª‚Ç‚±‚É“Ç‚Ýž‚Ü‚ê‚é‚Ì‚©

; ‰æ–Êƒ‚[ƒh‚ðÝ’è

		MOV		AL,0x13			; VGAƒOƒ‰ƒtƒBƒbƒNƒXA320x200x8bitƒJƒ‰[
		MOV		AH,0x00
		INT		0x10
		MOV		BYTE [VMODE],8	; ‰æ–Êƒ‚[ƒh‚ðƒƒ‚‚·‚éiCŒ¾Œê‚ªŽQÆ‚·‚éj
		MOV		WORD [SCRNX],320
		MOV		WORD [SCRNY],200
		MOV		DWORD [VRAM],0x000a0000

; ƒL[ƒ{[ƒh‚ÌLEDó‘Ô‚ðBIOS‚É‹³‚¦‚Ä‚à‚ç‚¤

		MOV		AH,0x02
		INT		0x16 			; keyboard BIOS
		MOV		[LEDS],AL


; PIC 关闭一切中断
;     根据AT兼容机的规格，如果要初始化PIC
;     必须在CLI之前进行，否则有时会挂起
;     随后进行PIC的初始化

		MOV		AL,0xff
		OUT		0x21,AL
		NOP						; OUT–½—ß‚ð˜A‘±‚³‚¹‚é‚Æ‚¤‚Ü‚­‚¢‚©‚È‚¢‹@Ží‚ª‚ ‚é‚ç‚µ‚¢‚Ì‚Å
		OUT		0xa1,AL

		CLI						; ‚³‚ç‚ÉCPUƒŒƒxƒ‹‚Å‚àŠ„‚èž‚Ý‹ÖŽ~

; CPU访问1MB以上的内存空间，
; 程序中使A20 GATE 信号线变成ON
; A20 GATE信号线变成ON后，内存1MB以上的区域才变成可访问状态
; 默认情况下，A20信号线为OFF,默认不能访问1MB以上的内存空间
; waitkdbout: wait_KBC_sendready
; waitkbdout是为了等待A20 Gate信号线的设置成功

		CALL	waitkbdout
		MOV		AL,0xd1
		OUT		0x64,AL
		CALL	waitkbdout
		MOV		AL,0xdf			; enable A20
		OUT		0x60,AL
		CALL	waitkbdout

; 切换到保护模式
; 保护模式下，段寄存器里存储的是段号，通过这个段号去GD table里可以找到段内存的起始地址
; 这 与16位模式下不同了，16位模式下，段寄存器的值*16就是段内存的开始地址
; 为什么叫保护？此模式下，不允许应用程序改变段的设定，

[INSTRSET "i486p"]				; 想要使用 486的指令 

		LGDT	[GDTR0]			; 设定临时GDT，全局段信息表
		MOV		EAX,CR0         ; CR0: control register 0 ,控制寄存器
		AND		EAX,0x7fffffff	; 将CRO 的第 31 bit设置为0，禁止分页
		OR		EAX,0x00000001	; 将CRO 的第 0  bit设置为1，切换到保护模式
		MOV		CR0,EAX         
		JMP		pipelineflush
pipelineflush:
		MOV		AX,1*8			;  所有段寄存器的地址都指向0x0008,相当于gdt+1
		MOV		DS,AX
		MOV		ES,AX
		MOV		FS,AX
		MOV		GS,AX
		MOV		SS,AX

; 将bootpack.c的代码传送到BOTPAK
; 因为在我们最终把 asmhead.nas和bootpack.c文件的编译文件直接连接起来生成了haribote.sys操作系统
; 所以，asmhead的最后一个标签 bootpack就是bootpack.c代码的开始地址
; 这就将c语言中的代码传送到了0x00280000处

		MOV		ESI,bootpack	; 源
		MOV		EDI,BOTPAK		; 目的地,BOTPAK 0x00280000
		MOV		ECX,512*1024/4
		CALL	memcpy

; 磁盘的数据传统到

; 将启动区程序复制到512字节到DSKCAC=0x00100000

		MOV		ESI,0x7c00		; “]‘—Œ³
		MOV		EDI,DSKCAC		; “]‘—æ
		MOV		ECX,512/4
		CALL	memcpy

; 将磁盘内容复制到0x00100200处

		MOV		ESI,DSKCAC0+512	; 源 DSKCAC0 +512 = 0x00008000 + 0x200 = 0x8200
		MOV		EDI,DSKCAC+512	; 目的地 DSKCAC + 512 = 0x00100000+ 0x200 = 0x0010 0200
		MOV		ECX,0
		MOV		CL,BYTE [CYLS]
		IMUL	ECX,512*18*2/4	; ƒVƒŠƒ“ƒ_”‚©‚çƒoƒCƒg”/4‚É•ÏŠ·
		SUB		ECX,512/4		; IPL‚Ì•ª‚¾‚¯·‚µˆø‚­
		CALL	memcpy

; asmhead 工作结束，后面就由bootpack来完成

; bootpack启动

		MOV		EBX,BOTPAK      ;BOTPAK 是bootpack.c代码所在的地址
		MOV		ECX,[EBX+16]    ;
		ADD		ECX,3			; ECX += 3;
		SHR		ECX,2			; ECX /= 4;
		JZ		skip			; 如果(EBX+16处的内容 +3 )/4==0,跳转到skip 
		MOV		ESI,[EBX+20]	; 源
		ADD		ESI,EBX
		MOV		EDI,[EBX+12]	; ‘目的地’
		CALL	memcpy
skip:
		MOV		ESP,[EBX+12]	; 
		JMP		DWORD 2*8:0x0000001b ;跳转到段2的1b地址开始执行,即bootpack.c处开始执行

waitkbdout:
		IN		 AL,0x64
		AND		 AL,0x02
		JNZ		waitkbdout		; AND‚ÌŒ‹‰Ê‚ª0‚Å‚È‚¯‚ê‚Îwaitkbdout‚Ö
		RET

memcpy:
		MOV		EAX,[ESI]
		ADD		ESI,4
		MOV		[EDI],EAX
		ADD		EDI,4
		SUB		ECX,1
		JNZ		memcpy			; ˆø‚«ŽZ‚µ‚½Œ‹‰Ê‚ª0‚Å‚È‚¯‚ê‚Îmemcpy‚Ö
		RET
; memcpy‚ÍƒAƒhƒŒƒXƒTƒCƒYƒvƒŠƒtƒBƒNƒX‚ð“ü‚ê–Y‚ê‚È‚¯‚ê‚ÎAƒXƒgƒŠƒ“ƒO–½—ß‚Å‚à‘‚¯‚é

		ALIGNB	16
GDT0:
		RESB	8				; NULL selector
		DW		0xffff,0x0000,0x9200,0x00cf	;  可以读写的段(segment) 32bit
		DW		0xffff,0x0000,0x9a28,0x0047	;  可以执行的段(segment) 32bit bootpack用

		DW		0
GDTR0:
		DW		8*3-1
		DD		GDT0

		ALIGNB	16
bootpack:
